home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / kerberos / pc / krb_libk.lha / Lib / KRB / SEND_KDC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-01  |  9.6 KB  |  315 lines

  1. /*
  2.  * $Source: /afs/athena.mit.edu/astaff/project/kerberos/src/lib/krb/RCS/send_to_kdc.c,v $
  3.  * $Author: jtkohl $
  4.  *
  5.  * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
  6.  *
  7.  * For copying and distribution information, please see the file
  8.  * <mit-copyright.h>.
  9.  */
  10.  
  11. #ifndef lint
  12. static char rcsid_send_to_kdc_c[] =
  13. "$Id: send_to_kdc.c,v 4.20 90/01/02 13:40:37 jtkohl Exp $";
  14. #endif /* lint */
  15.  
  16. #include <mit_copy.h>
  17.  
  18. #include <krb.h>
  19. #include <prot.h>
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <errno.h>
  24. #include <sys\types.h>
  25. #ifdef lint
  26. #include <sys\uio.h>            /* struct iovec to make lint happy */
  27. #endif /* lint */
  28. #include <sys\socket.h>
  29. #include <netinet\in.h>
  30. #include <netdb.h>
  31. #include <string.h>
  32.  
  33. #define S_AD_SZ sizeof(struct sockaddr_in)
  34.  
  35. extern int krb_debug;
  36.  
  37. int krb_udp_port = 0;
  38.  
  39. /* CLIENT_KRB_TIMEOUT indicates the time to wait before
  40.  * retrying a server.  It's defined in "krb.h".
  41.  */
  42. static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0};
  43. static char *prog = "send_to_kdc";
  44. static send_recv();
  45.  
  46. /*
  47.  * This file contains two routines, send_to_kdc() and send_recv().
  48.  * send_recv() is a static routine used by send_to_kdc().
  49.  */
  50.  
  51. /*
  52.  * send_to_kdc() sends a message to the Kerberos authentication
  53.  * server(s) in the given realm and returns the reply message.
  54.  * The "pkt" argument points to the message to be sent to Kerberos;
  55.  * the "rpkt" argument will be filled in with Kerberos' reply.
  56.  * The "realm" argument indicates the realm of the Kerberos server(s)
  57.  * to transact with.  If the realm is null, the local realm is used.
  58.  *
  59.  * If more than one Kerberos server is known for a given realm,
  60.  * different servers will be queried until one of them replies.
  61.  * Several attempts (retries) are made for each server before
  62.  * giving up entirely.
  63.  *
  64.  * If an answer was received from a Kerberos host, KSUCCESS is
  65.  * returned.  The following errors can be returned:
  66.  *
  67.  * SKDC_CANT    - can't get local realm
  68.  *              - can't find "kerberos" in /etc/services database
  69.  *              - can't open socket
  70.  *              - can't bind socket
  71.  *              - all ports in use
  72.  *              - couldn't find any Kerberos host
  73.  *
  74.  * SKDC_RETRY   - couldn't get an answer from any Kerberos server,
  75.  *          after several retries
  76.  */
  77.  
  78. send_to_kdc(pkt,rpkt,realm)
  79.     KTEXT pkt;
  80.     KTEXT rpkt;
  81.     char *realm;
  82. {
  83.     int i, f;
  84.     int no_host; /* was a kerberos host found? */
  85.     int retry;
  86.     int n_hosts;
  87.     int retval;
  88.     struct sockaddr_in to;
  89.     struct hostent *host, *hostlist;
  90.     char *cp;
  91.     char krbhst[MAX_HSTNM];
  92.     char lrealm[REALM_SZ];
  93.  
  94.     /*
  95.      * If "realm" is non-null, use that, otherwise get the
  96.      * local realm.
  97.      */
  98.     if (realm)
  99.     (void) strcpy(lrealm, realm);
  100.     else
  101.     if (krb_get_lrealm(lrealm,1)) {
  102.         if (krb_debug)
  103.         fprintf(stderr, "%s: can't get local realm\n", prog);
  104.         return(SKDC_CANT);
  105.     }
  106.     if (krb_debug)
  107.         printf("lrealm is %s\n", lrealm);
  108.     if (krb_udp_port == 0) {
  109.         register struct servent *sp;
  110.         if ((sp = getservbyname("kerberos","udp")) == 0) {
  111.             if (krb_debug)
  112.                 fprintf(stderr, "%s: Can't get kerberos/udp service\n",
  113.                         prog);
  114.             return(SKDC_CANT);
  115.         }
  116.         krb_udp_port = sp->s_port; 
  117.         if (krb_debug)
  118.             printf("krb_udp_port is %d\n", krb_udp_port);
  119.     }
  120.     bzero((char *)&to, S_AD_SZ);
  121.     hostlist = (struct hostent *) malloc(sizeof(struct hostent));
  122.     if (!hostlist)
  123.         return (/*errno */SKDC_CANT);
  124.     if ((f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  125.         if (krb_debug) {
  126.             fprintf(stderr,"%s: Can't open socket\n", prog);
  127.             }
  128.         return(SKDC_CANT);
  129.     }
  130.     /* from now on, exit through rtn label for cleanup */
  131.  
  132.     no_host = 1;
  133.     /* get an initial allocation */
  134.     n_hosts = 0;
  135.     for (i = 1; krb_get_krbhst(krbhst, lrealm, i) == KSUCCESS; ++i) {
  136.         if (krb_debug) {
  137.             printf("Getting host entry for %s...",krbhst);
  138.             (void) fflush(stdout);
  139.         }
  140.         host = gethostbyname(krbhst);
  141.         if (krb_debug) {
  142.             printf("%s.\n",
  143.                    host ? "Got it" : "Didn't get it");
  144.             (void) fflush(stdout);
  145.         }
  146.         if (!host)
  147.             continue;
  148.         no_host = 0;    /* found at least one */
  149.         n_hosts++;
  150.         /* preserve host network address to check later
  151.          * (would be better to preserve *all* addresses,
  152.          * take care of that later)
  153.          */
  154.         hostlist = (struct hostent *)
  155.             realloc((char *)hostlist,
  156.                     (unsigned)
  157.                     sizeof(struct hostent)*(n_hosts+1));
  158.         if (!hostlist)
  159.             return /*errno */SKDC_CANT;
  160.         bcopy((char *)host, (char *)&hostlist[n_hosts-1],
  161.               sizeof(struct hostent));
  162.         host = &hostlist[n_hosts-1];
  163.         cp = malloc((unsigned)host->h_length);
  164.         if (!cp) {
  165.             retval = /*errno */SKDC_CANT;
  166.             goto rtn;
  167.         }
  168.         bcopy((char *)host->h_addr, cp, host->h_length);
  169. /* At least Sun OS version 3.2 (or worse) and Ultrix version 2.2
  170.    (or worse) only return one name ... */
  171. #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40))
  172.         host->h_addr_list = (char **)malloc(sizeof(char *));
  173.         if (!host->h_addr_list) {
  174.             retval = /*errno */SKDC_CANT;
  175.             goto rtn;
  176.         }
  177. #endif /* ULTRIX022 || SunOS */
  178.         host->h_addr = cp;
  179.         bzero((char *)&hostlist[n_hosts],
  180.               sizeof(struct hostent));
  181.         to.sin_family = host->h_addrtype;
  182.         bcopy(host->h_addr, (char *)&to.sin_addr,
  183.               host->h_length);
  184.         to.sin_port = krb_udp_port;
  185.         if (send_recv(pkt, rpkt, f, &to, hostlist)) {
  186.             retval = KSUCCESS;
  187.             goto rtn;
  188.         }
  189.         if (krb_debug) {
  190.             printf("Timeout, error, or wrong descriptor\n");
  191.             (void) fflush(stdout);
  192.         }
  193.     }
  194.     if (no_host) {
  195.     if (krb_debug)
  196.         fprintf(stderr, "%s: can't find any Kerberos host.\n",
  197.             prog);
  198.         retval = SKDC_CANT;
  199.         goto rtn;
  200.     }
  201.     /* retry each host in sequence */
  202.     for (retry = 0; retry < CLIENT_KRB_RETRY; ++retry) {
  203.         for (host = hostlist; host->h_name != (char *)NULL; host++) {
  204.             to.sin_family = host->h_addrtype;
  205.             bcopy(host->h_addr, (char *)&to.sin_addr,
  206.                   host->h_length);
  207.             if (send_recv(pkt, rpkt, f, &to, hostlist)) {
  208.                 retval = KSUCCESS;
  209.                 goto rtn;
  210.             }
  211.         }
  212.     }
  213.     retval = SKDC_RETRY;
  214. rtn:
  215.     (void) soclose(f);
  216.     if (hostlist) {
  217.         register struct hostent *hp;
  218.         for (hp = hostlist; hp->h_name; hp++)
  219. #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40))
  220.             if (hp->h_addr_list) {
  221. #endif /* ULTRIX022 || SunOS */
  222.                 if (hp->h_addr)
  223.                     free(hp->h_addr);
  224. #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40))
  225.                 free((char *)hp->h_addr_list);
  226.             }
  227. #endif /* ULTRIX022 || SunOS */
  228.         free((char *)hostlist);
  229.     }
  230.     return(retval);
  231. }
  232.  
  233. /*
  234.  * try to send out and receive message.
  235.  * return 1 on success, 0 on failure
  236.  */
  237.  
  238. static send_recv(pkt,rpkt,f,_to,addrs)
  239.     KTEXT pkt;
  240.     KTEXT rpkt;
  241.     int f;
  242.     struct sockaddr_in *_to;
  243.     struct hostent *addrs;
  244. {
  245.     fd_set readfds;
  246.     register struct hostent *hp;
  247.     struct sockaddr_in from;
  248.     int sin_size;
  249.     int numsent;
  250.  
  251.     if (krb_debug) {
  252.         if (_to->sin_family == AF_INET)
  253.             printf("Sending message to %s...",
  254.                    inet_ntoa(_to->sin_addr));
  255.         else
  256.             printf("Sending message...");
  257.         (void) fflush(stdout);
  258.     }
  259.     if ((numsent = sendto(f,(char *)(pkt->dat), pkt->length, 0, 
  260.               (struct sockaddr *)_to,
  261.                           S_AD_SZ)) != pkt->length) {
  262.         if (krb_debug)
  263.             printf("sent only %d/%d\n",numsent, pkt->length);
  264.         return 0;
  265.     }
  266.     if (krb_debug) {
  267.         printf("Sent\nWaiting for reply...");
  268.         (void) fflush(stdout);
  269.     }
  270.     FD_ZERO(&readfds);
  271.     FD_SET(f, &readfds);
  272.     errno = 0;
  273.     /* select - either recv is ready, or timeout */
  274.     /* see if timeout or error or wrong descriptor */
  275.     if (select(f + 1, &readfds, (fd_set *)0, (fd_set *)0, &timeout) < 1
  276.         || !FD_ISSET(f, &readfds)) {
  277.         if (krb_debug) {
  278.             fprintf(stderr, "select failed: readfds=%x",
  279.                     readfds);
  280.             perror("");
  281.         }
  282.         return 0;
  283.     }
  284.     sin_size = sizeof(from);
  285.     if (recvfrom(f, (char *)(rpkt->dat), sizeof(rpkt->dat), 0,
  286.          (struct sockaddr *)&from, &sin_size)
  287.         < 0) {
  288.         if (krb_debug)
  289.             perror("recvfrom");
  290.         return 0;
  291.     }
  292.     if (krb_debug) {
  293.         printf("received packet from %s\n", inet_ntoa(from.sin_addr));
  294.         fflush(stdout);
  295.     }
  296.     for (hp = addrs; hp->h_name != (char *)NULL; hp++) {
  297.         if (!bcmp(hp->h_addr, (char *)&from.sin_addr.s_addr,
  298.                   hp->h_length)) {
  299.             if (krb_debug) {
  300.                 printf("Received it\n");
  301.                 (void) fflush(stdout);
  302.             }
  303.             return 1;
  304.         }
  305.         if (krb_debug)
  306.             fprintf(stderr,
  307.                     "packet not from %x\n",
  308.                     hp->h_addr);
  309.     }
  310.     if (krb_debug)
  311.         fprintf(stderr, "%s: received packet from wrong host! (%x)\n",
  312.                 "send_to_kdc(send_rcv)", from.sin_addr.s_addr);
  313.     return 0;
  314. }
  315.